﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;

namespace Dycox.Drawing
{
    public class DiagramRectangle : DiagramClosedShape
    {
        public DiagramRectangle(float left, float top, float width, float height)
            : this(new RectangleF(left, top, width, height))
        {

        }

        public DiagramRectangle(RectangleF bounds)
        {
            Bounds = bounds;
        }

        private RectangleF _bounds;

        public RectangleF Bounds
        {
            get { return _bounds; }
            set
            {
                if (_bounds != value)
                {
                    _bounds = value;
                    UpdateOutline();
                }
            }
        }

        private void UpdateOutline()
        {
            GraphicsPath path;

            if (_cornerRadius == default(float))
            {
                path = new GraphicsPath();
                path.AddRectangle(_bounds);
            }
            else
                path = GdiHelpers.CreateRoundedCornerPath(_bounds.X, _bounds.Y, _bounds.Width, _bounds.Height, _cornerRadius);

            this.OutlinePath = path;
            this.UpdateHotPoints();
        }

        private float _cornerRadius;

        public float CornerRadius
        {
            get { return _cornerRadius; }
            set
            {
                if (value < 0f || float.IsNaN(value) || float.IsInfinity(value))
                    throw new ArgumentOutOfRangeException();

                if (_cornerRadius != value)
                {
                    _cornerRadius = value;
                    UpdateOutline();
                }
            }
        }

        public static PointF[] GetHotPoints(RectangleF rect)
        {
            float l = rect.X, t = rect.Y, w = rect.Width, h = rect.Height, r = l + w, b = t + h;

            return new PointF[] {
                new PointF(l, t), new PointF(l + w * .25f, t), new PointF(l + w * .5f, t), new PointF(l + w * .75f, t), new PointF(r, t),
                new PointF(r, t + h * .25f), new PointF(r, t + h * .5f), new PointF(r, t + h * .75f), new PointF(r, b),
                new PointF(l + w * .75f, b), new PointF(l + w * .5f, b),  new PointF(l + w * .25f, b), new PointF(l, b),
                new PointF(l, t + h * .75f), new PointF(l, t + h * .5f), new PointF(l, t + h * .25f)
            };
        }

        private void UpdateHotPoints()
        {
            this.SetHotPoints(GetHotPoints(_bounds));
        }

        protected override void DrawShape(DrawShapeArgs args)
        {
            GraphicsPath path = base.OutlinePath;
            Graphics g = args.Graphics;

            Brush br = CreateFillBrush();
            if (br != null)
            {
                g.FillPath(br, path);
                br.Dispose();
            }

            DrawContent(args);

            Pen pen = CreateLinePen(false);
            if (pen != null)
            {
                g.DrawPath(pen, path);
                pen.Dispose();
            }
        }

        protected virtual void DrawContent(DrawShapeArgs args)
        {
        }

        protected StringFormat CreateStringFormat()
        {
            int ca = (int)this.TextAlign;
            int v, h = 1;

            for (v = 0; v < 3; v++)
            {
                h = ca & 0xf;

                if (h > 0)
                {
                    h /= 2;
                    break;
                }

                ca >>= 4;
            }

            StringFormat sf = new StringFormat();

            sf.Alignment = (StringAlignment)h;
            sf.LineAlignment = (StringAlignment)v;

            return sf;
        }

        private Color _patternColor;

        public Color PatternColor
        {
            get { return _patternColor; }
            set { _patternColor = value; }
        }

        private float _gradientAngle = 45f;

        [DefaultValue(45f)]
        public float GradientAngle
        {
            get { return _gradientAngle; }
            set { _gradientAngle = value; }
        }

        protected override Brush CreateFillBrush()
        {
            if (!_patternColor.IsEmpty)
                return CreateGradientBrush();
            else
                return base.CreateFillBrush();
        }

        private Brush CreateGradientBrush()
        {
            RectangleF rect = Bounds;
            LinearGradientBrush br = new LinearGradientBrush(rect, FillColor, _patternColor, _gradientAngle);
            
            return br;
        }


    }
}
